<?php


namespace App\Helpers\libs;


use Illuminate\Support\Facades\Log;

class BaiDuPan
{
    var $bs;
    var $token;
    var $vipBs;
    var $vipToken;
    public function __construct()
    {
        // TODO 多账号时从数据库获取账号信息
        $this->bs = config('pan.bduss');
        $this->token = config('pan.sToken');
        // $this->vipBs = config('pan.bduss');
        // $this->vipToken = config('pan.sToken');
        $this->vipBs = config('pan.vipBduss');
        $this->vipToken = config('pan.vipSToken');
    }

    /**
     * 解析分享链接
     * @param string $sid: 分享链接的唯一识别码
     * @param $bdclnd
     * @return int|mixed
     */
    public function getAnalysis(string $sid, $bdclnd)
    {
        $url = 'https://pan.baidu.com/s/' . $sid;
        $headers = array(
            "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.514.1919.810 Safari/537.36",
            "Cookie: BDUSS=" . $this->bs . ";STOKEN=" . $this->token . ";BDCLND=" . $bdclnd . ";"
        );
        // 如果不修改这里,则要修改配置文件ini
        $result = $this->get($url, $headers);

        if (preg_match('/locals.mset\((\{.*?\})\);/', $result, $matches)) {
            return json_decode($matches[1], true, 512, JSON_BIGINT_AS_STRING);
        } else {
            if (strstr($result, "Redirecting to") != false) {
                // 账号BDUSS或STOKEN失效
                return [
                    'errno' => -1,
                    'file_list' => [],
                ];
            } else {
                // 页面已升级，请重新修改脚本
                return [
                    'errno' => -2,
                    'file_list' => [],
                ];
            }
        }
    }

    /**
     * 获取文件夹的子目录
     * @param string $dir
     * @param string $bdclnd
     * @param string $shareId
     * @param string $uk
     * @return mixed
     */
    public function getDirFiles(string $dir, string $bdclnd, string $shareId, string $uk)
    {
        $url = 'https://pan.baidu.com/share/list?shareid=' . $shareId .
            '&uk=' . $uk . '&dir=' . urlencode($dir);
        $header = array(
            "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.514.1919.810 Safari/537.36",
            "Cookie: BDUSS=" . $this->bs . ";STOKEN=" . $this->token . ";BDCLND=" . $bdclnd . ";",
            "Referer: https://pan.baidu.com/disk/home"
        );
        return json_decode($this->get($url, $header), true);
    }

    /**
     * 获取直链地址
     * @param string $fs_id
     * @param string $timestamp
     * @param string $sign
     * @param string $randsk
     * @param string $share_id
     * @param string $uk
     * @param string $bdstoken
     * @param bool $isnoualink
     * @param int $app_id
     * @return mixed
     */
    public function getDownLink(
        string $fs_id, string $timestamp,
        string $sign, string $randsk, string $share_id,
        string $uk, string $bdstoken, bool $isnoualink,
        int $app_id = 250528
    )
    {

        if ($isnoualink) {
            $url = 'https://pan.baidu.com/api/sharedownload?app_id=' . $app_id .
                '&channel=chunlei&clienttype=0&sign=' . $sign . '&timestamp=' .
                $timestamp . '&web=1&bdstoken=' . $bdstoken; // 获取直链 50MB以内
        } else {
            $url = 'https://pan.baidu.com/api/sharedownload?app_id=' . $app_id .
                '&channel=chunlei&clienttype=12&sign=' . $sign . '&timestamp=' .
                $timestamp . '&web=1'; // 获取下载链接
        }

        $data = "encrypt=0" . "&extra=" . urlencode('{"sekey":"' . urldecode($randsk) . '"}') . "&fid_list=[$fs_id]" . "&primaryid=$share_id" . "&uk=$uk" . "&product=share&type=nolimit";
        $header = array(
            "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.514.1919.810 Safari/537.36",
            "Cookie: BDUSS=" . $this->bs . ";STOKEN=" . $this->token . ";BDCLND=" . $randsk . ";",
            "Referer: https://pan.baidu.com/disk/home"
        );
        return json_decode($this->post($url, $data, $header), true);
    }

    /**
     * 获取高速下载地址
     * @param $dLink
     * @param false $smallFile
     * @return false|string
     */
    public function getRealLink($dLink, $smallFile = false)
    {
        if ($smallFile) {
            $headerArray = array(
                'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.514.1919.810 Safari/537.36',
                'Cookie: BDUSS=' . $this->bs . ';');
        } else {
            $headerArray = array(
                'User-Agent: LogStatistic',
                'Cookie: BDUSS=' . $this->vipBs . ';'
            );
        }
        $getRealLink = $this->getHeaders($dLink, $headerArray);
        $getRealLink = strstr($getRealLink, "Location");
        $getRealLink = substr($getRealLink, 10);
        if ($smallFile) {
            $realLink = $this->getSubstr($getRealLink, "https://", "\r\n"); // 注意，这里小文件是https
        } else {
            $realLink = $this->getSubstr($getRealLink, "http://", "\r\n"); // 删除 http://
        }
        return $realLink;
    }

    public function getSign($sid, $lnd)
    {
        $url = "https://pan.baidu.com/share/tplconfig?surl=$sid&fields=sign,timestamp&channel=chunlei&web=1&app_id=250528&clienttype=0";
        $header = array(
            "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.514.1919.810 Safari/537.36",
            "Cookie: BDUSS=" . $this->bs . ";STOKEN=" . $this->token . ";BDCLND=" . $lnd . ";"
        );
        $result = $this->get($url, $header);
        return json_decode($result, true, 512, JSON_BIGINT_AS_STRING);
    }

    /**
     * 获取响应头中的DBCLND数据，用于后续文件列表
     * 这个参数包含在Cookie里面
     * @param $sid
     * @param $pwd
     * @return false|mixed|string
     */
    public function getBdLND($sid, $pwd)
    {
        $header = array('User-Agent: netdisk');
        $url = 'https://pan.baidu.com/share/wxlist?clienttype=25&shorturl=' .
            $sid . '&pwd=' . $pwd; // 使用新方法获取，减少花费的时间
        $result = $this->getHeaders($url, $header);
        Log::info('请求头中的信息：');

        if (strstr($result, "BDCLND") == false) {
            // 修复：部分链接不存在bdclnd
            $bdclnd = false;
        } else {
            $bdclnd = $this->getSubstr($result, 'BDCLND=', ';');
        }
        if ($bdclnd) {
            return $bdclnd;
        } else {
            // 获取BDCLND失败，尝试使用老方法获取
            $header = $this->getHeaders("https://pan.baidu.com/s/" . $sid, []);
            Log::info($header);
            $bdclnd = preg_match('/BDCLND=(.+?);/', $header, $matches);
            if ($bdclnd) {
                return $matches[1];
            } else {
                return '';
            }
        }
    }

    /**
     * 获取分享链接的唯一ID
     */
    public function getSid($url)
    {
        $sid = '';
        if (strpos($url, 'surl') !== false) {
            // 旧的分享链接
            // https://pan.baidu.com/share/init?surl=QaZU_7usGgAYV2GWeS5uqQ
            $paramStr = explode('?', $url)[1];
            $items = explode('&', $paramStr);
            foreach ($items as $item) {
                $arr = explode('=', $item);
                if ($arr[0] == 'surl') {
                    $sid = '1' . $arr[1];
                    break;
                }
            }
        } else {
            $url = explode('#', $url)[0];   // 去除#后面部分
            $url = explode('?', $url)[0];   // 去除参数部分
            $items = explode('/', $url);
            $sid = $items[count($items) - 1];
        }
        return $sid;
    }

    /**
     * 获取请求的响应头
     * @param string $url
     * @param array $header
     * @return false|string
     */
    private function getHeaders(string $url, array $headers)
    {
        $ch = curl_init($url);
        $this->setCurl($ch, $headers);
        curl_setopt($ch, CURLOPT_HEADER, true); // 返回响应头
        curl_setopt($ch, CURLOPT_NOBODY, true); // 只要响应头
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
        $response = curl_exec($ch);
        $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); // 获得响应头大小
        $result = substr($response, 0, $header_size); // 根据头大小获取头信息
        curl_close($ch);
        return $result;
    }

    /**
     * CURL通用设置
     * @param $ch
     * @param array $headers
     */
    private function setCurl(&$ch, array $headers)
    {
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 忽略证书
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); // 不检查证书与域名是否匹配（2为检查）
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 以字符串返回结果而非输出
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); // 请求头
    }

    /**
     * 获取字符串中的键值对的值
     * @param string $str
     * @param string $leftStr
     * @param string $rightStr
     * @return false|string
     */
    private function getSubstr(string $str, string $key, string $value)
    {
        $left = strpos($str, $key);
        $right = strpos($str, $value, $left);
        if ($left < 0 || $right < $left) return '';
        $left += strlen($key);
        return substr($str, $left, $right - $left);
    }

    /**
     * GET请求
     * @param string $url
     * @param array $headers
     * @return bool|string
     */
    private function get(string $url, array $headers)
    {
        $ch = curl_init($url);
        $this->setCurl($ch, $headers);
        $result = curl_exec($ch);
        curl_close($ch);
        return $result;
    }

    /**
     * post请求
     * @param string $url
     * @param $data
     * @param array $header
     * @return bool|string
     */
    private function post(string $url, $data, array $header)
    {
        $ch = curl_init($url);
        $this->setCurl($ch, $header);
        curl_setopt($ch, CURLOPT_POST, true); // POST 方法
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data); // POST 的数据
        $result = curl_exec($ch);
        curl_close($ch);
        return $result;
    }
}
